package thread;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: 86185
 * Date: 2023-07-28
 * Time: 14:48
 */
class MyBlockingQueue {

    //加上volatile保证内存可见性

    //使用一个String类型的数组来保存元素, 假设这里只存String
    private volatile String[] items = new String[1000];
    //指向队列的头部
    private volatile int head = 0;
    //指向队列的尾部的下一个元素, 队列中有效数组的元素范围[head, tail)
    private volatile int tail = 0;
    //当前的元素个数
    private volatile int size = 0;


    /**
     * 线程安全: 先给put和take进行加锁, 保证在多线程调用的时候能够线程安全
     *          实现阻塞:
     *           + 当队列空了或者满了, 就引发阻塞.
     * @param src
     * @throws InterruptedException
     */
    public void put(String src) throws InterruptedException {
        synchronized (this) {
            while (size >= items.length) {
                //队列满了, 阻塞, 当队列有空间后再被唤醒
                this.wait();
            }
            items[tail] = src;
            tail++;
            size++;
            if(tail >= items.length) {
                tail = 0;
            }
            //size++后, 原本空的队列有元素了, 所以因队列空而阻塞的线程可以被唤醒了
            this.notify();
        }
    }
    public String take() throws InterruptedException {
        synchronized (this) {
            while (size == 0) {
                //队列为空, 阻塞, 当队列中有元素后再被唤醒
                this.wait();
            }
            String elem = items[head];
            head++;
            size--;
            if (head >= items.length) {
                head = 0;
            }
            //size--后, 原本满的队列不满了, 所以因队列满而阻塞的线程可以被唤醒了
            this.notify();
            return elem;
        }
    }
}
public class Demo20 {
    public static void main(String[] args) {
        MyBlockingQueue queue = new MyBlockingQueue();
        Thread thread1 = new Thread(() -> {
            int count = 0;
            while (true) {
                try {
                    queue.put(count + "");
                    System.out.println("生产元素 : " + count);
                    count++;
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        Thread thread2 = new Thread(() -> {
            while (true) {
                try {
                    String s = queue.take();
                    System.out.println("消费 : " + s);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        thread1.start();
        thread2.start();
    }
}
